/* 
 * Copyright 2011 kOSMik.
 * This file is part of kOSMik.
 * 
 * kOSMik is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * kOSMik is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with kOSMik.  If not, see <http://www.gnu.org/licenses/>.
 *  
 * kOSMik:
 * Open Street Map - Editor.
 * http://code.google.com/p/swp-dv-ws2010-osm-2/
 */

package de.fuberlin.kosmik.gui.view.adapter;

import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

/**
 * The ListWithHeadersAdapter is a abstract adapter class which handles the
 * getView method for lists that contain of standard items and headers.
 * 
 * @author micha
 * 
 * @param <T> Class of the items in the Adapter.
 * @param <H> Class of header's ViewHolder.
 * @param <I> Class of standard item's ViewHolder.
 */
public abstract class ListWithHeadersAdapter<T extends ListItem, H extends ViewHolder<T>, I extends ViewHolder<T>>
		extends ArrayAdapter<T> implements TextWatcher {

	private int headerLayout;
	private int itemLayout;
	private LayoutInflater mInflater;

	/**
	 * Constructor of the Adapter.
	 * 
	 * @param context caller's context
	 * @param headerLayoutResId Res id of the layout which is used for the
	 *            headers in the list.
	 * @param itemLayoutResId Res id of the layout which is used for the
	 *            standard items in the list.
	 */
	public ListWithHeadersAdapter(Context context, int headerLayoutResId, int itemLayoutResId) {
		super(context, itemLayoutResId);
		headerLayout = headerLayoutResId;
		itemLayout = itemLayoutResId;
		mInflater = LayoutInflater.from(context);
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		I holderItem;
		H holderHeader;
		T listItem;
		View convView = convertView;
		listItem = this.getItem(position);

		if (listItem.isHeader()) {
			// if conView is null or of the wrong type we have to inflate a new
			// view
			if (convView == null || !((ViewHolder<?>) convView.getTag()).isHeader()) {
				convView = mInflater.inflate(headerLayout, null);
				holderHeader = findViewsOfHeader(convView);
				convView.setTag(holderHeader);
			} else {
				holderHeader = (H) convView.getTag();
			}
			setViewsOfHeader(holderHeader, listItem);
			return convView;
		}
		// if item is no header
		if (convView == null || ((ViewHolder<?>) convView.getTag()).isHeader()) {
			convView = mInflater.inflate(itemLayout, null);
			holderItem = findViewsOfItem(convView);
			convView.setTag(holderItem);
		} else {
			holderItem = (I) convView.getTag();
		}
		setViewsOfItem(holderItem, listItem);
		return convView;
	}

	/**
	 * Creates a new ViewHolder of a Header, finds all relevant Views and
	 * returns the ViewHolder object.
	 * 
	 * @param convView parentView which has HEADER_LAYOUT.
	 * 
	 * @return new ViewHolder of a Header with its View.
	 */
	abstract H findViewsOfHeader(View convView);

	/**
	 * Sets all Views of a HeaderViewHolder object.
	 * 
	 * @param headerHolder which holds all Views that should be set with
	 *            content.
	 * @param listItem current item in the list.
	 */
	abstract void setViewsOfHeader(H headerHolder, T listItem);

	/**
	 * Creates a new ViewHolder of an Item, finds all relevant Views and returns
	 * the ViewHolder object.
	 * 
	 * @param convView parentView which has ITEM_LAYOUT.
	 * 
	 * @return new ViewHolder of a Item with its View.
	 */
	abstract I findViewsOfItem(View convView);

	/**
	 * Sets all Views of a ItemViewHolder object.
	 * 
	 * @param itemHolder which holds all Views that should be set with content.
	 * @param listItem current item in the list.
	 */
	abstract void setViewsOfItem(I itemHolder, T listItem);

	// methods of the TextWatcher interface.
	@Override
	public void afterTextChanged(Editable s) {
		// not used
	}

	@Override
	public void beforeTextChanged(CharSequence s, int start, int count, int after) {
		// not used
	}

	@Override
	public void onTextChanged(CharSequence s, int start, int before, int count) {
		this.getFilter().filter(s);
	}

	/**
	 * Resets search results so that all items of the list are shown.
	 */
	public void resetSearch() {
		this.getFilter().filter("");
	}

}